package com.bjpowernode.filter;

import com.alibaba.fastjson.JSON;
import com.bjpowernode.model.Result;
import com.bjpowernode.constant.LoginConstant;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component
public class TokenCheckFilter extends OncePerRequestFilter {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 拦截器
     * 除了几个放行的接口
     * 其他的接口都需要拦截 检查token
     *
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 设置编码格式
        response.setContentType("application/json;charset=utf-8");
        // 拿到请求的地址
        String path = request.getRequestURI();
        // 判断是否有我们需要放行的地址,先走的过滤器在走的security所以需要放行
        for (String allPaths : LoginConstant.ALLOW_URL) {
            if (allPaths.equals(path)) {
                // 放行地址
                filterChain.doFilter(request, response);
                return;
            }
        }
        // 放行swagger的地址,swagger有很多子路径和swagger-*或swagger-*-这样的路径,所以使用包含写法
        if (path.contains("swagger") || path.contains("api") || path.contains("v2") || path.contains("v3")) {
            filterChain.doFilter(request, response);
            return;
        }

        // 校验token信息
        // 拿到请求头信息
        String header = request.getHeader(LoginConstant.AUTHORIZATION);
        // 判断请求头里面是否有信息
        if (StringUtils.hasText(header)) {
            // 分割请求头里面的token信息,只需要拿到我们使用uuid生成的编号即可
            String token = header.replaceAll(LoginConstant.TOKEN_PREFIX, "");
            // 判断是否有token信息
            if (StringUtils.hasText(token)) {
                // 从redis里面取出我们存入的token进行比较,就知道是否登录过
                String userStr = stringRedisTemplate.opsForValue().get(LoginConstant.LOGIN_PREFIX + token);
                // 判断userStr里面是否有值,因为这里面我们存入的是上下文信息
                if (StringUtils.hasText(userStr)) {
                    // 使用json转换为对象,然后存入到上下文里面去
                    UsernamePasswordAuthenticationToken authenticationToken = JSON.parseObject(userStr, UsernamePasswordAuthenticationToken.class);
                    // 放到上下文中去,让security去取,完成自动登录到过程
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                    // 放行
                    filterChain.doFilter(request,response);
                    return;
                }
            }
        }
        // 如果不满足以上添加直接拦截让其重新登录
        Result<String> result = new Result<>();
        result.setCode(401);
        result.setMsg("登录以过期,请重新登录.");
        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writeValueAsString(request);
        PrintWriter writer = response.getWriter();
        writer.write(s);
        writer.flush();
        writer.close();
    }
}
